#include <gmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <unistd.h>
#include <sys/resource.h>
#include <sys/time.h>

#include "gauss_legendre.h"
#include "borwein.h"
#include "monte_carlo.h"



int main (int argc, char* argv[]) {

	int option;
	struct timeval begin_time_s, end_time_s, begin_time_p, end_time_p;
	

	// tratamento de erro
	if (argc < 2) {
		printf("> Erro, esta faltando o argumento da opcao.\n");
		return (-1);
	} else if (argc > 2) {
		printf("> Erro, ha mais de um argumento, verifique.\n");
		return (-1);
	}

	option = atoi(argv[1]);
	if ((option < 1) && (option > 3)) {
		printf("> Erro, nao existe essa opcao de algoritmo.\n");
		return (-1);
	}


	printf("================= Calculo do valor PI =================\n");

	// opcoes para executar qualquer algoritmo da escolha do usuario
	switch (option) {
		case 1: {
			printf("> 1) Algoritmo Gauss Legendre\n");

			printf("> Sequencial\n");
			gettimeofday(&begin_time_s, NULL);	// inicio da medicao do tempo
			calculationPiSeqGaussLegendre();	// calculo do pi sequencial
			gettimeofday(&end_time_s, NULL);	// fim da medicao do tempo

			printf("\n> Paralelo\n");
			gettimeofday(&begin_time_p, NULL);	// inicio da medicao do tempo
			calculationPiParGaussLegendre();	// calculo do pi paralelo
			gettimeofday(&end_time_p, NULL);	// fim da medicao do tempo
		} break;
		case 2: {
			printf("> 2) Algoritmo Borwein\n");

			printf("> Sequencial\n");
			gettimeofday(&begin_time_s, NULL);	// inicio da medicao do tempo
			calculationPiSeqBorwein();			// calculo do pi sequencial
			gettimeofday(&end_time_s, NULL);	// fim da medicao do tempo

			printf("\n> Paralelo\n");
			gettimeofday(&begin_time_p, NULL);	// inicio da medicao do tempo
			calculationPiParBorwein();			// calculo do pi paralelo
			gettimeofday(&end_time_p, NULL);	// fim da medicao do tempo		
		} break;
		case 3: {
			printf("> 3) Algoritmo Monte Carlo\n");

			printf("> Sequencial\n");
			gettimeofday(&begin_time_s, NULL);	// inicio da medicao do tempo
			calculationPiSeqMonteCarlo();		// calculo do pi sequencial
			gettimeofday(&end_time_s, NULL);	// fim da medicao do tempo

			printf("\n> Paralelo\n");
			gettimeofday(&begin_time_p, NULL);	// inicio da medicao do tempo
			calculationPiParMonteCarlo();		// calculo do pi paralelo
			gettimeofday(&end_time_p, NULL);	// fim da medicao do tempo
		} break;
	}


	// calculo do tempo
	printf("\n> T(1): %.4lf segundos\n",
		(((end_time_s.tv_sec - begin_time_s.tv_sec) * 1000000 + (end_time_s.tv_usec - begin_time_s.tv_usec)) * 0.000001));
	printf("> T(N): %.4lf segundos\n",
		(((end_time_p.tv_sec - begin_time_p.tv_sec) * 1000000 + (end_time_p.tv_usec - begin_time_p.tv_usec)) * 0.000001));
	printf("> SpeedUp(T(1)/T(N)): %.4lf\n",
		((((end_time_s.tv_sec - begin_time_s.tv_sec) * 1000000 + (end_time_s.tv_usec - begin_time_s.tv_usec)) * 0.000001) /
		(((end_time_p.tv_sec - begin_time_p.tv_sec) * 1000000 + (end_time_p.tv_usec - begin_time_p.tv_usec)) * 0.000001)));

	return (0);
}
